大家好,我是 Ryan,這篇文章是我參與 iThome 2022 鐵人賽時與大家分享使用 Nuxt 3 串接 Google OAuth 登入的額外分享,因為在使用 Nuxt 3 串接 Google OAuth 其實等同於在 Vue 3 中做實現,所以獨立了一篇 Vue 3 的範例來分享給大家。
為了讓專案更乾淨,本篇範例使用的是 Vue 3 + Vite 的模板,大家也可以參考下列指令做建立。
npm create vite@latest vue3-google-oauth-example -- --template vue
首先,我們需要有一組 Google OAuth 使用的 Client ID,你可以到 Google Console 新增一個「OAuth 2.0 用戶端 ID」,這裡我就不再贅述網頁應用程式用的申請過程。
這邊提醒,在建立 OAuth Client ID 時,已授權的 JavaScript 來源,記得填寫上您的正式環境或開發環境的 Domain,且建議使用 HTTPS。
完成後,記得保管好用戶端密碼,用戶端 ID (Client ID) 是我們稍後會需要的,用戶端編號格式大概如:
168152363730-b37gnijdpa2rdvvbq0qc29cjh4082t3b.apps.googleusercontent.com
接下來,安裝 Vue 的 Google OAuth 插件,這邊使用的是 vue3-google-login,也有不錯的說明文件可以參考。
使用 NPM 安裝 vue3-google-login。
npm install -D vue3-google-login
接著我們在元件中可以直接使用 <GoogleLogin>
元件,並添加一個 callback
屬性。
<script setup>
import { ref } from 'vue'
const data = ref()
const callback = (response) => {
data.value = response
}
</script>
<template>
<div>
<GoogleLogin :callback="callback" />
<p>
{{ data }}
</p>
</div>
</template>
<style scoped>
p {
margin-top: 12px;
word-break: break-all;
}
</style>
接著我們使用 npm run dev
來啟動開發伺服器,就能發現使用 Google 帳號登入成功後,所返回的 Credential。
你可以在 <GoogleLogin>
元件添加 prompt
屬性並設為 true
,這樣就能同時啟用 Google 一鍵登入 (One Tap prompt) 的功能囉!
<GoogleLogin :callback="callback" prompt/>
或者也可以在 onMounted
中呼叫 vue3-google-login 的 googleOneTap()
方法,來單獨使用 One Tap prompt。
<script setup>
import { onMounted } from 'vue'
import { googleOneTap } from 'vue3-google-login'
onMounted(() => {
googleOneTap()
.then((response) => {
console.log(response)
})
.catch((error) => {
console.error(error)
})
})
</script>
如果你想自訂登入按鈕的樣式,可以在 <GoogleLogin>
的預設插槽 (Slot) 做建立。
<template>
<GoogleLogin :callback="callback">
<button>使用 Google 進行登入</button>
</GoogleLogin>
</template>
使用自訂按鈕會讓 OAuth 流程稍微有點不一樣,當你登入成功後預設會回傳 Auth Code。
如果設定屬性 popup-type="TOKEN"
,則回傳 Access Token。
<template>
<GoogleLogin :callback="callback" popup-type="TOKEN">
<button>使用 Google 進行登入</button>
</GoogleLogin>
</template>
googleTokenLogin()
在元件中我們也可以自己建立 handleGoogleAccessTokenLogin
點擊事件,呼叫 googleTokenLogin()
方法並傳入設定在 Runtime Config 中的 Google Client ID,這樣點擊登入按鈕就能處理 Google 登入取得 Access Token。
<script setup>
import { ref } from 'vue'
import { googleTokenLogin } from 'vue3-google-login'
const GOOGLE_CLIENT_ID = '這邊放上你的 Google Client ID'
const data = ref()
const handleGoogleAccessTokenLogin = () => {
googleTokenLogin({
clientId: GOOGLE_CLIENT_ID
}).then((response) => {
data.value = response
})
}
</script>
建立一個登入按鈕來呼叫 handleGoogleAccessTokenLogin
點擊事件。
<template>
<div>
<button
type="button"
@click="handleGoogleAccessTokenLogin"
>
使用 Google 進行登入
</button>
</template>
使用 vue3-google-login 提供的 googleTokenLogin()
方法,我們就能取得 Google 使用者的 Access Token 囉!
googleAuthCodeLogin()
我們也可以使用 googleAuthCodeLogin()
來取得 Auth Code。
<script setup>
import { ref } from 'vue'
import { googleAuthCodeLogin } from 'vue3-google-login'
const GOOGLE_CLIENT_ID = '這邊放上你的 Google Client ID'
const data = ref()
const handleGoogleAuthCodeLogin = () => {
googleAuthCodeLogin({
clientId: GOOGLE_CLIENT_ID
}).then((response) => {
data.value = response
})
}
</script>
建立一個登入按鈕來呼叫 handleGoogleAuthCodeLogin
點擊事件。
<template>
<div>
<button
type="button"
@click="handleGoogleAuthCodeLogin"
>
使用 Google 進行登入
</button>
</template>
取得的就會是 Auth Code。
當使用者於前端成功登入後,通常會傳至後端進行登入或記錄使用者,再產生使用於網站的 Token、Cookie 或 Session 等,以供後續的網站驗證做使用。
我們可使用 google-auth-library 於後端進行一系列的驗證或取得使用者資訊。
使用 NPM 安裝 google-auth-library。
npm install -D google-auth-library
接下來,我們就能依照不同的登入方式取得的 Credential
、Access Token
或 Auth Code
送至後端做驗證。
Access Token
import { OAuth2Client } from 'google-auth-library'
export default (async (accessToken) => {
const oauth2Client = new OAuth2Client()
oauth2Client.setCredentials({ access_token: accessToken })
const userInfo = await oauth2Client
.request({
url: 'https://www.googleapis.com/oauth2/v3/userinfo'
})
.then((response) => response.data)
.catch(() => null)
oauth2Client.revokeCredentials()
return {
id: userInfo.sub,
name: userInfo.name,
avatar: userInfo.picture,
email: userInfo.email,
emailVerified: userInfo.email_verified,
}
})
Credential
在元件中,我們使用的登入方式如果是Google 預設渲染的按鈕或 One Tap prompt,回傳值就會包含 Credential
,我們將就可使用下面修改後的 Server API 進行驗證。
import { OAuth2Client } from 'google-auth-library'
export default (async (credential) => {
const oauth2Client = new OAuth2Client()
const ticket = await oauth2Client.verifyIdToken({
idToken: credential,
})
const payload = ticket.getPayload()
return {
id: payload.sub,
name: payload.name,
avatar: payload.picture,
email: payload.email,
emailVerified: payload.email_verified
}
})
Auth Code
import { OAuth2Client } from 'google-auth-library'
export default (async (authCode) => {
const oauth2Client = new OAuth2Client({
clientId: '你的 Google Client ID',
clientSecret: '你的 Google Client Secret',
redirectUri: '你的 Google Redirect Uri'
})
let { tokens } = await oauth2Client.getToken(authCode)
client.setCredentials({ access_token: tokens.access_token })
const userInfo = await oauth2Client
.request({
url: 'https://www.googleapis.com/oauth2/v3/userinfo'
})
.then((response) => response.data)
.catch(() => null)
oauth2Client.revokeCredentials()
return {
id: userInfo.sub,
name: userInfo.name,
avatar: userInfo.picture,
email: userInfo.email,
emailVerified: userInfo.email_verified,
}
})
這篇文章記錄了實現了串接 Google OAuth 登入,大家可以在依照使用情境自己挑選登入方式並將 Access Token
等其他資訊發送至後端進行驗證,後續也能將使用者資訊儲存到資料庫中,有了資料庫我們就能依照使用者資訊,來比對資料庫進行註冊、驗證登入及產生後續的 Session 或 Cookie 等。
感謝大家的閱讀,歡迎大家給予建議 :)
此外我正在參與 iThome 鐵人賽,主題是 Nuxt 3 學習筆記,
如果對 Nuxt 3 系列感興趣,可以訂閱接收通知,也歡迎分享給喜歡或正在學習 Nuxt 3 的夥伴。
版主你好,想請問後半部驗證的部分都是在後端執行嗎?
您好,是的,伺服器端驗證的段落開始,就是在後端執行的程式來做驗證
非常謝謝!
您好,我想要請教關於後端驗證的部分
目前是有想要嘗試,直接在vue3環境中做驗證,參考範例程式碼後,發現在 中引入
import { OAuth2Client } from "google-auth-library"; 會報出錯誤。
想詢問說,是我引入的方式有錯誤嗎?
關於後端驗證的部分,是需要在後端做使用例如範例中的是以 Nuxt 起的 Server API 來做後端的驗證。
您可以先將完整的範例專案下載下來進行本地的測試,觀察專案的結構與釐清前端與後端的 Server API。
google-auth-library 套件是 Node.js Client,所以在瀏覽器上是無法做執行的。
好的 謝謝你的說明~
想另外請問,驗證部分是只能透過後端做驗證處理嗎?
如果我前端想要做驗證的話,目前是只能透過 Nuxt 起的 Server API或用NODE.JS 來做後端的驗證這樣是嗎?
驗證部分,不是只能在後端做,而是在前端實作會不安全。
若是在前端實作,您的驗證、解密流程與金鑰都是暴露在前端,所以若不依賴後端的驗證手段,都是有可能被使用者惡意竄改或偽造。
Nuxt 是一個可以完成全端的框架,剛好有 Server API 的部分可以實作,你也可以將 Nuxt 當作單純的 Vue 專案或網站,後端 API 使用其他語言來實作,例如 Python、Rust 等都是可行的。
所以你的後端驗證,並沒有限制說一定要 Nuxt 或 Node.js。
好的 謝謝你仔細的說明, 我明白原因了 真的謝謝~~~
對於驗證的安全性也比較理解了。
你好,我在使用CSP的時候遇上了問題,這個vue3-google-login有辦法幫他加上nonce或是取得他的sha256嗎?